#if BACKEND
using MultiAgentsServer.Scripts.Database;
using MultiAgentsServer.Scripts.Tools;


#endif
using MultiAgentsShared;
using OpenAI.ObjectModels;
using OpenAI.ObjectModels.RequestModels;

namespace MultiAgentsClient.ChatDataStructures;

public class ChatMessageData : SerializableObjectBase
{
    public int Id;
    public int senderId;

    public string role = "";
    public string content = "";
    public string author = "";

    public Dictionary<int, (string fileName, string fileContent)> images = [];
    public Dictionary<int, (string fileName, string fileContent)> textFiles = [];

    public List<int>? historyMessagesIdList = [];

    public string? toolCallId;
    public List<ToolCall>? toolCalls;

    public int tokens;
    public bool msgStreamFinished;
    private bool toolsCallFinished = false;
    private readonly SemaphoreSlim semaphore = new(1, 1);
    public DateTime TimeAdded;
    public bool IsClientMsg => role == StaticValues.ChatMessageRoles.User;
    public bool ToolCallsRequireApproval = false;

    public ChatMessageData() { }

    public ChatMessageData(int Id, int senderId, string role, string content, List<int>? historyMessagesIdList, string author, Dictionary<int, (string fileName, string fileContent)> images, Dictionary<int, (string fileName, string fileContent)> textFiles, string? toolCallId, int tokens, bool msgStreamFinished, DateTime TimeAdded, List<ToolCall>? toolCalls = null)
    {
        this.Id = Id;
        this.role = role;
        this.content = content;
        this.author = author;
        this.historyMessagesIdList = historyMessagesIdList;
        this.images = images;
        this.textFiles = textFiles;
        this.toolCallId = toolCallId;
        this.tokens = tokens;
        this.msgStreamFinished = msgStreamFinished;
        this.TimeAdded = TimeAdded;
        this.senderId = senderId;
        this.toolCalls = toolCalls;
    }

    public bool TryCompleteToolsCall()
    {
        semaphore.WaitAsync();

        try
        {
            if (toolsCallFinished == false)
            {
                toolsCallFinished = true;
                return toolsCallFinished;
            }
            else
            {
                return false;
            }
        }
        finally
        {
            semaphore.Release();
        }
    }

    public static ChatMessageData FromUser(int messageId, int senderId, string message, List<int>? historyMessagesIdList, Dictionary<int, (string fileName, string fileContent)> images, Dictionary<int, (string fileName, string fileContent)> textFiles, int token, string author, DateTime TimeAdded)
    {
        return new ChatMessageData(messageId, senderId, StaticValues.ChatMessageRoles.User, message, historyMessagesIdList, ChatStringExtension.NameAsSystemReadable(author), images, textFiles, null, token, true, TimeAdded);
    }

    public static ChatMessageData FromSystem(int messageId, int senderId, string message, List<int>? historyMessagesIdList, int token, DateTime TimeAdded)
    {
        return new ChatMessageData(messageId, senderId, StaticValues.ChatMessageRoles.System, message, historyMessagesIdList, "system", [], [], null, token, true, TimeAdded);
    }

    public static ChatMessageData FromAssistant(int messageId, int senderId, string message, List<int>? historyMessagesIdList, int token, string author, bool streamFinished, DateTime TimeAdded, List<ToolCall>? toolCalls = null)
    {
        return new ChatMessageData(messageId, senderId, StaticValues.ChatMessageRoles.Assistant, message, historyMessagesIdList, ChatStringExtension.NameAsSystemReadable(author), [], [], null, token, streamFinished, TimeAdded, toolCalls);
    }

    public static ChatMessageData FromTool(int messageId, int senderId, string toolCallId, string toolCallResult, List<int>? historyMessagesIdList, int token, DateTime TimeAdded)
    {
        return new ChatMessageData(messageId, senderId, StaticValues.ChatMessageRoles.Tool, toolCallResult, historyMessagesIdList, "tool", [], [], toolCallId, token, true, TimeAdded);
    }

    public void SetToolCalls(List<ToolCall> toolCalls, bool requireApproval)
    {
        this.toolCalls = toolCalls;
        ToolCallsRequireApproval = requireApproval;
    }

#if FRONTEND
    public ChatMessageDisp ToDisp()
    {
        foreach (KeyValuePair<int, (string fileName, string fileContent)> image in images)
        {
            content += $"\r<filename {image.Value.fileName}><fileid {image.Key}>";
        }

        foreach (KeyValuePair<int, (string fileName, string fileContent)> file in textFiles)
        {
            content += $"\r<filename {file.Value.fileName}><fileid {file.Key}>";
        }

        return new ChatMessageDisp(Id, content ?? "", role, role == StaticValues.ChatMessageRoles.User ? null : author + " :", historyMessagesIdList, senderId, TimeAdded, msgStreamFinished, toolCalls?.ToList(), ToolCallsRequireApproval);
    }

#endif

#if BACKEND
    public static ChatMessageData FromMessageDB(MessageDB chatMessageDb, int token, List<FilesDB>? filesDBList = null)
    {
        ChatMessageData message;

        Dictionary<int, (string fileName, string fileContent)> images = [];
        Dictionary<int, (string fileName, string fileContent)> textFiles = [];

        if (chatMessageDb.Role == StaticValues.ChatMessageRoles.User)
        {
            foreach (int imageId in chatMessageDb.ImageList.Keys)
            {
                string content = "";
                if (filesDBList != null)
                {
                    FilesDB file = filesDBList?.FirstOrDefault(file => file.Id == imageId) ?? throw Debug.ShouldNotHappen();
                    content = file.Content;
                }

                images.Add(imageId, (chatMessageDb.ImageList[imageId], content));
            }

            foreach (int fileId in chatMessageDb.TextFileList.Keys)
            {
                string content = "";
                if (filesDBList != null)
                {
                    FilesDB file = filesDBList?.FirstOrDefault(file => file.Id == fileId) ?? throw Debug.ShouldNotHappen();
                    content = file.Content;
                }

                textFiles.Add(fileId, (chatMessageDb.TextFileList[fileId], content));
            }

            message = FromUser(chatMessageDb.Id, chatMessageDb.UserId, chatMessageDb.Content, chatMessageDb.HistoryMessagesIdList, images, textFiles, token, chatMessageDb.Author, chatMessageDb.Time);
        }
        else if (chatMessageDb.Role == StaticValues.ChatMessageRoles.Assistant)
        {
            List<ToolCall>? toolCalls = null;
            if (string.IsNullOrEmpty(chatMessageDb.ToolCalls) == false)
            {
                toolCalls = FromJson<List<ToolCall>>(chatMessageDb.ToolCalls);
            }

            message = FromAssistant(chatMessageDb.Id, chatMessageDb.AgentId, chatMessageDb.Content, chatMessageDb.HistoryMessagesIdList, token, chatMessageDb.Author, true, chatMessageDb.Time, toolCalls);
        }
        else if (chatMessageDb.Role == StaticValues.ChatMessageRoles.System)
        {
            message = FromSystem(chatMessageDb.Id, chatMessageDb.UserId, chatMessageDb.Content, chatMessageDb.HistoryMessagesIdList, token, chatMessageDb.Time);
        }
        else if (chatMessageDb.Role == StaticValues.ChatMessageRoles.Tool)
        {
            message = FromTool(chatMessageDb.Id, chatMessageDb.AgentId, chatMessageDb.ToolCallId, chatMessageDb.Content, chatMessageDb.HistoryMessagesIdList, token, chatMessageDb.Time);
        }
        else
        {
            throw Debug.ShouldNotHappen();
        }

        return message;
    }
#endif
}
